/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkSdp.h"
#include "MkUtil/MkLog.h"
#include "MkUtil/MkUtil.h"
#include "MkUtil/MkBase64.h"

CMkSdpAttribute::CMkSdpAttribute(const MkString& Field, const MkString& Value/*=""*/)
    :m_Field(Field)
    , m_Value(Value)
{

}

Uint32 CMkSdpAttribute::ToString(MkString& Content)
{
    if (m_Field.empty()) {
        return InvalidParams;
    }
    Content = m_Field;
    if (!m_Value.empty()) {
        Content += ":" + m_Value;
    }
    return NoneError;
}

Uint32 CMkSdpAttribute::ParseContent(const MkString& Content)
{
    size_t nPos = Content.find(":");
    if (MkString::npos == nPos) {
        m_Field = Content;
    } else {
        m_Field = Content.substr(0, nPos);
        m_Value = Content.substr(nPos + 1);
    }
    return NoneError;
}

CMkSdpFmt::CMkSdpFmt()
    :m_Payload(0)
    , m_ClockRate(0)
    , m_EncodingParams(0)
    , m_H264PacketMode(0)
    , m_H264ProfileLevelId(0)
{

}

CMkSdpFmt::CMkSdpFmt(Uint32 Payload, const MkString& EncodingName, Uint32 ClockRate, Uint32 EncodingParams /* = 0 */)
    : m_Payload(Payload)
    , m_EncodingName(EncodingName)
    , m_ClockRate(ClockRate)
    , m_EncodingParams(EncodingParams)
    , m_H264ProfileLevelId(0)
    , m_H264PacketMode(0)
{

}

Uint32 CMkSdpFmt::ParseContent(const MkString& Content)
{
    MkVectorString vecStr;
    Uint32 ErrorCode = CMkUtil::StringSplit(Content, " ", vecStr);
    if (NoneError != ErrorCode && vecStr.size() < 2) {
        MkErrorLog("split sdp fmt:%s failed\n", Content.c_str());
        return InvalidParams;
    }
    MkVectorString vecStr1;
    ErrorCode = CMkUtil::StringSplit(vecStr[1], "/", vecStr1);
    MkCheckErrorLog(ErrorCode, "split sdp fmt params:%s failed\n", vecStr[1].c_str());
    m_Payload = std::stoi(vecStr[0]);
    m_EncodingName = vecStr1[0];
    if (vecStr1.size() > 1) {
        m_ClockRate = std::stoi(vecStr1[1]);
    }
    if (vecStr1.size() > 2) {
        m_EncodingParams = std::stoi(vecStr1[2]);
    }
    return NoneError;
}

Uint32 CMkSdpFmt::ToString(OUT MkString& Content)
{
    Content += std::to_string(m_Payload) + " " + m_EncodingName;
    if (0 != m_ClockRate) {
        Content += "/" + std::to_string(m_ClockRate);
    }
    if (0 != m_EncodingParams) {
        Content += "/" + std::to_string(m_EncodingParams);
    }
    return NoneError;
}

Uint32 CMkSdpFmt::ToFmtpString(OUT MkString& Content)
{
    if ("H264" == m_EncodingName) {
        if (0 != m_H264ProfileLevelId) {
            Int8 pBuf[Len16] = { 0 };
            snprintf(pBuf, Len16, "%x", m_H264ProfileLevelId);
            Content += "profile-level-id:" + MkString(pBuf) + "; ";
        }
        if (0 != m_H264PacketMode) {
            Content += "packetization-mode=" + std::to_string(m_H264PacketMode) + "; ";
        }
        if (!m_VideoBase64Pps.empty()) {
            Content += "sprop-parameter-sets=" + m_VideoBase64Sps + "," + m_VideoBase64Pps + "; ";
        }

    } else if ("H265" == m_EncodingName) {
        Content += "profile-space=" + std::to_string(m_H265ProfileSpace) + ";profile-id=" + std::to_string(m_H265ProfileId) + ";tier-flag=" + std::to_string(m_H265TierFlag) + ";level-id=" + std::to_string(m_H265LevelId) + ";interop-constraints=" + m_H265InteropConstraints + ";";
        if (!m_VideoBase64Vps.empty()) {
            Content += "sprop-vps=" + m_VideoBase64Vps + "; sprop-sps=" + m_VideoBase64Sps + "; sprop-pps=" + m_VideoBase64Pps + "; ";
        }
    }
    MkMapString::iterator it = m_MapOtherFmtp.begin();
    for (; it != m_MapOtherFmtp.end(); it++) {
        Content += it->first + "=" + it->second + "; ";
    }
    if (!Content.empty()) {
        Content = std::to_string(m_Payload) + " " + Content;
    }

    if (CMkUtil::EndByString(Content, "; ")) {
        Content = Content.substr(0, Content.size() - 2);
    }
    return NoneError;
}

Uint32 CMkSdpFmt::AddFmtp(const MkString& Fmtp)
{
    MkVectorString VecStr;
    Uint32 ErrorCode = CMkUtil::StringSplit(Fmtp, "; ", VecStr);
    MkCheckErrorLog(ErrorCode, "split fmtp:%s failed\n", Fmtp.c_str());
    MkVectorString::iterator it = VecStr.begin();
    size_t nPos = 0;
    for (; it != VecStr.end(); it++) {
        nPos = it->find("=");
        if (MkString::npos == nPos) {
            m_MapOtherFmtp[*it] = MkString("");
        } else {
            MkString strKey = it->substr(0, nPos);
            MkString strValue = it->substr(nPos + 1);
            if ("sprop-vps" == strKey) {
                SetBase64Vps(strValue);
            } else if ("sprop-sps" == strKey) {
                SetBase64Sps(strValue);
            } else  if ("sprop-pps" == strKey) {
                SetBase64Pps(strValue);
            } else if ("sprop-parameter-sets" == strKey) {
                size_t nFind = strValue.find(",");
                if (MkString::npos != nFind) {
                    SetBase64Sps(strValue.substr(0, nFind));
                    SetBase64Pps(strValue.substr(nFind + 1));
                }
            } else if ("profile-level-id" == strKey) {
                m_H264ProfileLevelId = std::stoi(strValue);
            } else if ("packetization-mode" == strKey) {
                m_H264PacketMode = std::stoi(strValue);
            } else {
                m_MapOtherFmtp[strKey] = strValue;
            }
        }
    }
    return NoneError;
}

void CMkSdpFmt::SetBase64Sps(const MkString& Sps)
{
    m_VideoBase64Sps = Sps;
    MkBase64Decode(Sps, m_VideoSps);
}

void CMkSdpFmt::SetBase64Pps(const MkString& Pps)
{
    m_VideoBase64Pps = Pps;
    MkBase64Decode(Pps, m_VideoPps);
}

void CMkSdpFmt::SetBase64Vps(const MkString& Vps)
{
    m_VideoBase64Vps = Vps;
    MkBase64Decode(Vps, m_VideoVps);
}

void CMkSdpFmt::SetSps(const MkString& Sps)
{
    m_VideoSps = Sps;
    MkBase64Encode(Sps, m_VideoBase64Sps);
}

void CMkSdpFmt::SetPps(const MkString& Pps)
{
    m_VideoPps = Pps;
    MkBase64Encode(Pps, m_VideoBase64Pps);
}

void CMkSdpFmt::SetVps(const MkString& Vps)
{
    m_VideoVps = Vps;
    MkBase64Encode(Vps, m_VideoBase64Vps);
}

CMkSdpMedia::CMkSdpMedia()
    : m_Port(0)
    , m_NumberOfPort(0)
    , m_RtcpWithRtp(FALSE)
    , m_PlayStartTime(-1.0)
    , m_PlayEndTime(-1.0)
    , m_AddressProtocolType(0)
    , m_VideoWidth(0)
    , m_VideoHeight(0)
    , m_VideoFrameRate(0)
    , m_Protocol("RTP/AVP")
{

}

Uint32 CMkSdpMedia::GetBandWidth() const
{
    if (m_BandWidth.Empty()) {
        return 0;
    }
    return std::stoi(m_BandWidth.GetBandWidth());
}

Uint32 CMkSdpMedia::SetMediaType(const MkString& MediaType)
{
    m_MediaType = MediaType;
    return NoneError;
}

Uint32 CMkSdpMedia::SetPort(Uint16 Port)
{
    m_Port = Port;
    return NoneError;
}

Uint32 CMkSdpMedia::SetNumberOfPort(Uint8 NumberOfPort)
{
    m_NumberOfPort = NumberOfPort;
    return NoneError;
}

Uint32 CMkSdpMedia::SetProtocol(const MkString& Protocol)
{
    m_Protocol = Protocol;
    return NoneError;
}

Uint32 CMkSdpMedia::AddExtend(const MkString& Key, const MkString& Value)
{
    m_MapExtend[Key] = Value;
    return NoneError;
}

Uint32 CMkSdpMedia::AddFmt(const CMkSdpFmt& SdpFmt)
{
    m_MapFmt[SdpFmt.GetPayload()] = SdpFmt;
    return NoneError;
}

Uint32 CMkSdpMedia::AddFmtp(Uint32 Playload, const MkString& Fmtp)
{
    MkMap<Uint32, CMkSdpFmt>::iterator it = m_MapFmt.find(Playload);
    if (it != m_MapFmt.end()) {
        it->second.AddFmtp(Fmtp);
    }
    return NoneError;
}

Uint32 CMkSdpMedia::ToString(MkString& Content)
{
    if (m_MediaType.empty() || m_Protocol.empty() || m_MapFmt.empty()) {
        return InvalidParams;
    }
    Uint32 ErrorCode = NoneError;
    Content = "m=" + m_MediaType + " " + std::to_string(m_Port);
    if (0 != m_NumberOfPort) {
        Content += "/" + std::to_string(m_NumberOfPort);
    }
    Content += " " + m_Protocol;

    MkString FmtAttr;

    MkMap<Uint32, CMkSdpFmt>::iterator itFmt = m_MapFmt.begin();
    for (; itFmt != m_MapFmt.end(); itFmt++) {
        MkString SdpFmt;
        MkString SdpFmtp;
        Content += " " + std::to_string(itFmt->first);
        ErrorCode = itFmt->second.ToString(SdpFmt);
        MkCheckErrorLog(ErrorCode, "attr to string failed\n");
        ErrorCode = itFmt->second.ToFmtpString(SdpFmtp);
        MkCheckErrorLog(ErrorCode, "to fmtp buffer failed\n");
        FmtAttr += "a=rtpmap:" + SdpFmt + MkEndLine;
        if (!SdpFmtp.empty()) {
            FmtAttr += "a=fmtp:" + SdpFmtp + MkEndLine;
        }
    }
    if (!m_SubType.empty()) {
        Content += " " + m_SubType;
    }
    Content += MkEndLine;
    //add connect
    if (!m_Connection.Empty()) {
        MkString StrConnection;
        m_Connection.ToString(StrConnection);
        Content += "c=" + StrConnection + MkEndLine;
    }
    if (!m_BandWidth.Empty()) {
        MkString StrBandWidth;
        m_BandWidth.ToString(StrBandWidth);
        Content += "b=" + StrBandWidth + MkEndLine;
    }
    if (0 != m_VideoHeight && 0 != m_VideoHeight) {
        Content += "a=x-dimensions:" + std::to_string(m_VideoWidth) + "," + std::to_string(m_VideoHeight) + MkEndLine;
    }
    if (0 != m_VideoFrameRate) {
        Content += "a=x-framerate:" + std::to_string(m_VideoFrameRate) + MkEndLine;
    }
    if (!m_ControlUri.empty()) {
        Content += "a=control:" + m_ControlUri + MkEndLine;
    }

    MkString AttrContent;
    MkVector<CMkSdpAttribute>::iterator itAtti = m_VecAttri.begin();
    for (; itAtti != m_VecAttri.end(); itAtti++) {
        ErrorCode = (itAtti)->ToString(AttrContent);
        MkCheckErrorLog(ErrorCode, "attr to string failed\n");
        Content += "a=" + AttrContent + MkEndLine;
    }
    Content += FmtAttr;
    MkMapString::iterator itExtend = m_MapExtend.begin();
    for (; itExtend != m_MapExtend.end(); itExtend++) {
        Content += itExtend->first + "=" + itExtend->second + MkEndLine;
    }
    return NoneError;
}

Uint32 CMkSdpMedia::ParseContent(const MkString& Content)
{
    //content is m=xxx to next m=xxx
    MkString ReadLine;
    Uint32 nPos = 0;
    MkVectorString vecStr;
    Uint32 ErrorCode = CMkUtil::BufferReadLine(Content, nPos, ReadLine);
    MkCheckErrorLog(ErrorCode, "read media line failed\n");
    ErrorCode = CMkUtil::StringSplit(ReadLine, "=", vecStr);
    if (NoneError != ErrorCode || vecStr.size() < 2) {
        MkErrorLog("split string:%s invalid\n", ReadLine.c_str());
        return InvalidParams;
    }
    if ("m" != vecStr[0]) {
        MkErrorLog("parse media line failed\n");
        return InvalidParams;
    }
    ErrorCode = ParseMediaHeader(vecStr[1]);
    MkCheckErrorLog(ErrorCode, "parse media header failed\n");

    size_t nFind = 0;
    MkString strKey, strValue;
    while (nPos < Content.size()) {
        vecStr.clear();
        ErrorCode = CMkUtil::BufferReadLine(Content, nPos, ReadLine);
        MkCheckErrorLog(ErrorCode, "read sdp attr line failed\n");
        nFind = ReadLine.find("=");
        if (MkString::npos == nFind) {
            continue;
        }
        strKey = ReadLine.substr(0, nFind);
        strValue = ReadLine.substr(nFind + 1);
        if ("a" == strKey) {
            CMkSdpAttribute Attr;
            if (NoneError != Attr.ParseContent(strValue)) {
                continue;
            }
            if ("rtpmap" == Attr.GetField()) {
                CMkSdpFmt SdpFmt;
                if (NoneError == SdpFmt.ParseContent(Attr.GetValue())) {
                    AddFmt(SdpFmt);
                }
            } else if ("fmtp" == Attr.GetField()) {
                MkString Fmtp = Attr.GetValue();
                size_t f = Fmtp.find(" ");
                if (MkString::npos != f) {
                    AddFmtp(std::stoi(Fmtp.substr(0, f)), Fmtp.substr(f + 1));
                }
            } else if ("type" == Attr.GetField()) {
                m_SessionType = Attr.GetValue();
            } else if ("control" == Attr.GetField()) {
                m_ControlUri = Attr.GetValue();
            } else if ("rtcp-mux" == Attr.GetField()) {
                m_RtcpWithRtp = TRUE;
            } else if ("range" == Attr.GetField()) {
                ParseAttributeRang(Attr.GetValue());
            } else if ("source-filter" == Attr.GetField()) {
                ParseAttributeSourceFilter(Attr.GetValue());
            } else if ("key-mgmt" == Attr.GetField()) {
                ParseAttributeMikey(Attr.GetValue());
            } else if ("x-dimensions" == Attr.GetField()) {
                ParseAttributeVideoSolution(Attr.GetValue());
            } else if ("framerate" == Attr.GetField() || "x-framerate" == Attr.GetField()) {
                m_VideoFrameRate = std::stoi(Attr.GetValue());
            } else {
                m_VecAttri.push_back(Attr);
            }
        } else if ("c" == strKey) {
            m_Connection.ParseContent(strValue);
        } else if ("b" == strKey) {
            m_BandWidth.ParseContent(strValue);
        } else if ("k" == strKey) {
            MkVectorString vecKey;
            ErrorCode = CMkUtil::StringSplit(strValue, ":", vecKey);
            MkCheckErrorLog(ErrorCode, "split key:%s failed\n", strValue.c_str());
            m_MapEncryptionKey[vecKey[0]] = vecKey.size() < 2 ? "" : vecKey[1];
        } else if ("i" == strKey) {
            m_SessionDesc = strValue;
        } else { //extern
            m_MapExtend[strKey] = strValue;
        }
    }
    return NoneError;
}

Uint32 CMkSdpMedia::GetExtendValue(const MkString& strKey, MkString& strValue) const
{
    Uint32 ErrorCode = InvalidParams;
    MkMapString::const_iterator it = m_MapExtend.find(strKey);
    if (it != m_MapExtend.end()) {
        strValue = it->second;
        ErrorCode = NoneError;
    }
    return ErrorCode;
}

Uint32 CMkSdpMedia::ParseMediaHeader(const MkString& Header)
{
    MkVectorString vecStr;
    Uint32 ErrorCode = CMkUtil::StringSplit(Header, " ", vecStr);
    if (NoneError != ErrorCode || vecStr.size() < 3) {
        return InvalidParams;
    }
    m_MediaType = vecStr[0];
    MkVectorString vecPort;
    ErrorCode = CMkUtil::StringSplit(vecStr[1], "/", vecPort);
    MkCheckErrorLog(ErrorCode, "split port:%s failed\n", vecStr[1].c_str());
    m_Port = std::stoi(vecPort[0]);
    if (vecPort.size() > 1) {
        m_NumberOfPort = std::stoi(vecPort[1]);
    }
    m_Protocol = vecStr[2];
    for (size_t i = 3; i < vecStr.size(); i++) {
        try {
            m_MapFmt[std::stoi(vecStr[i])] = CMkSdpFmt();
        } catch (const std::exception& ex) {
            MkWarningLog("input string:%s error:%s\n", vecStr[i].c_str(), ex.what());
            m_SubType = vecStr[i];
            break;
        }
    }
    return NoneError;
}

Uint32 CMkSdpMedia::ParseAttributeRang(const MkString& RangContent)
{
    size_t NtpFind = RangContent.find("ntp=");
    size_t ClockFind = RangContent.find("clock=");
    size_t TimeFind = RangContent.find("-");
    if (MkString::npos == TimeFind) {
        MkErrorLog("rang content(%s) is corrent:%d\n", RangContent.c_str());
        return InvalidParams;
    }
    if (MkString::npos != NtpFind) {
        MkString strStart = RangContent.substr(NtpFind + strlen("ntp="), TimeFind - NtpFind - strlen("ntp="));
        if ("now" == strStart) {
            m_PlayEndTime = m_PlayStartTime = 0.0;
        } else {
            MkString strEnd = RangContent.substr(TimeFind + 1);
            m_PlayStartTime = std::stod(strStart);
            m_PlayEndTime = std::stod(strEnd);
        }
    }
    if (MkString::npos != ClockFind) {
        MkString strStart = RangContent.substr(ClockFind + strlen("ntp="), TimeFind - ClockFind - strlen("clock="));
        MkString strEnd = RangContent.substr(TimeFind + 1);
        m_AbsStartTime = CMkTime(strStart.substr(0, strStart.size() - 1));//20100929T095038.00Z delete Z
        m_AbsEndTime = CMkTime(strEnd.substr(0, strEnd.size() - 1));
    }
    return NoneError;
}

Uint32 CMkSdpMedia::ParseAttributeSourceFilter(const MkString& FilterContent)
{
    size_t nFind = FilterContent.find("incl IN IP4 * ");
    if (MkString::npos != nFind) {
        m_SourceName = FilterContent.substr(nFind);
        m_AddressProtocolType = AF_INET;
        return NoneError;
    }
    nFind = FilterContent.find("incl IN IP6 * ");
    if (MkString::npos != nFind) {
        m_SourceName = FilterContent.substr(nFind);
        m_AddressProtocolType = AF_INET6;
    }
    return NoneError;
}

Uint32 CMkSdpMedia::ParseAttributeMikey(const MkString& MikeyContent)
{
    size_t nFind = MikeyContent.find("mikey ");
    if (MkString::npos != nFind) {
        m_Mikey = MikeyContent.substr(nFind);
    }
    return NoneError;
}

Uint32 CMkSdpMedia::ParseAttributeVideoSolution(const MkString& SolutionContent)
{
    size_t nFind = SolutionContent.find(",");
    if (MkString::npos != nFind) {
        m_VideoWidth = std::stoi(SolutionContent.substr(0, nFind));
        m_VideoHeight = std::stoi(SolutionContent.substr(nFind + 1));
    }
    return NoneError;
}

CMkSdpMedia::~CMkSdpMedia()
{
}

CMkSdpTime::CMkSdpTime(Uint64 StartTime, Uint64 EndTime, const MkVectorString& RepeatTimes/*=MkVectorString()*/)
    : m_StartTime(StartTime)
    , m_EndTime(EndTime)
    , m_RepeatTimes(RepeatTimes)
{

}

CMkSdpTime::CMkSdpTime()
    : m_StartTime(0)
    , m_EndTime(0)
{

}

Uint32 CMkSdpTime::ParseRepeatTimes(const MkString& RepeatContent)
{
    Uint32 ErrorCode = CMkUtil::StringSplit(RepeatContent, " ", m_RepeatTimes);
    if (NoneError != ErrorCode || m_RepeatTimes.empty()) {
        MkErrorLog("parse repeat times(%s) failed\n", RepeatContent.c_str());
        return InvalidParams;
    }
    return NoneError;
}

Uint32 CMkSdpTime::AddRepeatTimes(const MkVectorString& RepeatTimes)
{
    m_RepeatTimes = RepeatTimes;
    return NoneError;
}

Uint32 CMkSdpTime::ToString(MkString& Content)
{
    Content = std::to_string(m_StartTime) + " " + std::to_string(m_EndTime);
    return NoneError;
}

Uint32 CMkSdpTime::RepeatTimesToString(MkString& RepeatContent)
{
    if (m_RepeatTimes.empty()) {
        return InvalidParams;
    }
    MkVectorString::iterator it = m_RepeatTimes.begin();
    MkVectorString::iterator itLast = m_RepeatTimes.end()--;
    for (; it != m_RepeatTimes.end(); it++) {
        RepeatContent += *it;
        if (itLast != it) {
            RepeatContent += " ";
        }
    }
    return NoneError;
}

Uint32 CMkSdpTime::ParseContent(const MkString& Content)
{
    MkVectorString vecStr;
    Uint32 ErrorCode = CMkUtil::StringSplit(Content, " ", vecStr);
    if (NoneError != ErrorCode || vecStr.size() < 2) {
        MkErrorLog("parse sdp time(%s) failed\n", Content.c_str());
        return InvalidParams;
    }
    m_StartTime = std::stoi(vecStr[0]);
    m_EndTime = std::stoi(vecStr[1]);
    return NoneError;
}

CMkSdpBandWidth::CMkSdpBandWidth(const MkString& Modifier, const MkString& BandWidth)
    :m_Modifier(Modifier)
    , m_BandWidth(BandWidth)
{

}

Uint32 CMkSdpBandWidth::ToString(MkString& Content)
{
    if (m_Modifier.empty() || m_BandWidth.empty()) {
        return InvalidParams;
    }
    Content = m_Modifier + ":" + m_BandWidth;
    return NoneError;
}

Uint32 CMkSdpBandWidth::ParseContent(const MkString& Content)
{
    MkVectorString vecStr;
    Uint32 ErrorCode = CMkUtil::StringSplit(Content, ":", vecStr);
    if (NoneError != ErrorCode || vecStr.size() < 2) {
        MkErrorLog("paser band width(%s) failed\n", Content.c_str());
        return InvalidParams;
    }
    m_Modifier = vecStr[0];
    m_BandWidth = vecStr[1];
    return NoneError;
}

CMkSdpConnection::CMkSdpConnection()
    : m_AddrMulticastTtl(0)
    , m_AddrMulticastCount(0)
{

}

CMkSdpConnection::CMkSdpConnection(const MkString& NetType, const MkString&AddrType, const MkString& Addr, Uint8 MulticastTtl/* = 0*/, Uint8 MulticastCount/* = 0*/)
    : m_NetType(NetType)
    , m_AddrType(AddrType)
    , m_Addr(Addr)
    , m_AddrMulticastTtl(MulticastTtl)
    , m_AddrMulticastCount(MulticastCount)
{

}

Uint32 CMkSdpConnection::ToString(MkString& Content)
{
    if (m_NetType.empty() || m_AddrType.empty() || m_Addr.empty()) {
        return NoneError;
    }
    Content = m_NetType + " " + m_AddrType + " " + m_Addr;
    if (0 != m_AddrMulticastTtl) {
        Content += "/" + std::to_string(m_AddrMulticastTtl);
    }
    if (0 != m_AddrMulticastCount) {
        Content += "/" + std::to_string(m_AddrMulticastCount);
    }
    return NoneError;
}

BOOL CMkSdpConnection::Empty()
{
    return m_NetType.empty() || m_AddrType.empty() || m_Addr.empty();
}

Uint32 CMkSdpConnection::ParseContent(const MkString& Content)
{
    MkVectorString vecStr;
    Uint32 ErrorCode = CMkUtil::StringSplit(Content, " ", vecStr);
    if (NoneError != ErrorCode || vecStr.size() < 3) {
        MkErrorLog("parse sdp connection(%s) failed\n", Content.c_str());
        return InvalidParams;
    }
    m_NetType = vecStr[0];
    m_AddrType = vecStr[1];
    MkVectorString vecAddr;
    ErrorCode = CMkUtil::StringSplit(vecStr[2], "/", vecAddr);
    if (NoneError != ErrorCode || vecAddr.empty() || vecAddr[0].empty()) {
        MkErrorLog("parse addr(%s) failed\n", vecStr[2].c_str());
        return InvalidParams;
    }
    m_Addr = vecAddr[0];
    if (vecAddr.size() > 1) {
        m_AddrMulticastTtl = std::stoi(vecAddr[1]);
    }
    if (vecAddr.size() > 2) {
        m_AddrMulticastCount = std::stoi(vecAddr[2]);
    }
    return NoneError;
}

CMkOrigin::CMkOrigin(const MkString& UserName, const MkString& SessionId, const MkString& SessionVersion, const MkString& NetType,
    const MkString& AddrType, const MkString& Addr)
    : m_UserName(UserName)
    , m_SessionId(SessionId)
    , m_SessionVersion(SessionVersion)
    , m_NetType(NetType)
    , m_AddrType(AddrType)
    , m_Addr(Addr)
{

}

Uint32 CMkOrigin::ToString(MkString& OriginContent)
{
    if (Empty()) {
        return InvalidParams;
    }
    OriginContent = m_UserName + " " + m_SessionId + " " + m_SessionVersion + " " + m_NetType + " " + m_AddrType + " " + m_Addr;
    return NoneError;
}

BOOL CMkOrigin::Empty()
{
    return m_UserName.empty()
        || m_SessionId.empty()
        || m_NetType.empty()
        || m_AddrType.empty()
        || m_Addr.empty();
}

Uint32 CMkOrigin::ParseContent(const MkString& Content)
{
    MkVectorString vecParam;
    Uint32 ErrorCode = CMkUtil::StringSplit(Content, " ", vecParam);
    MkCheckErrorLog(ErrorCode, "spilt origin(%s) failed\n", Content.c_str());
    if (vecParam.size() < 6) {
        return InvalidParams;
    }
    m_UserName = vecParam[0];
    m_SessionId = vecParam[1];
    m_SessionVersion = vecParam[2];
    m_NetType = vecParam[3];
    m_AddrType = vecParam[4];
    m_Addr = vecParam[5];
    return NoneError;
}


CMkSdp::CMkSdp()
{

}

Uint32 CMkSdp::SetVersion(const MkString& Version)
{
    m_Version = Version;
    return NoneError;
}

Uint32 CMkSdp::SetOrigin(const CMkOrigin& Origin)
{
    m_Origin = Origin;
    return NoneError;
}

Uint32 CMkSdp::SetSessionName(const MkString& SessionName)
{
    m_SessionName = SessionName;
    return NoneError;
}

Uint32 CMkSdp::SetSessionDesc(const MkString& SessionDesc)
{
    m_SessionDesc = SessionDesc;
    return NoneError;
}

Uint32 CMkSdp::SetUri(const MkString& Uri)
{
    m_Uri = Uri;
    return NoneError;
}

Uint32 CMkSdp::SetEmail(const MkString& Email)
{
    m_Email = Email;
    return NoneError;
}

Uint32 CMkSdp::SetPhoneNumber(const MkString& PhoneNumber)
{
    m_PhoneNumber = PhoneNumber;
    return NoneError;
}

Uint32 CMkSdp::SetConnection(const CMkSdpConnection& Connection)
{
    m_Connection = Connection;
    return NoneError;
}

Uint32 CMkSdp::SetBandWidth(const CMkSdpBandWidth& BandWidth)
{
    m_BandWidth = BandWidth;
    return NoneError;
}

Uint32 CMkSdp::SetTime(const CMkSdpTime& SdpTime)
{
    m_TimeDesc = SdpTime;
    return NoneError;
}

Uint32 CMkSdp::SetTimeZones(const MkMapString& Zones)
{
    m_MapTimeZones = Zones;
    return NoneError;
}

Uint32 CMkSdp::SetEncrytionKey(const MkMapString& Encryption)
{
    m_MapEncryptionKey = Encryption;
    return NoneError;
}

Uint32 CMkSdp::SetAttribute(const MkVector<CMkSdpAttribute>& Attributes)
{
    m_VecAttribute = Attributes;
    return NoneError;
}

Uint32 CMkSdp::AddAttribute(const CMkSdpAttribute& Attr)
{
    m_VecAttribute.push_back(Attr);
    return NoneError;
}

Uint32 CMkSdp::SetMedia(const MkVector<CMkSdpMedia>& Media)
{
    m_VecMedia = Media;
    return NoneError;
}

Uint32 CMkSdp::AddMedia(const CMkSdpMedia& Media)
{
    m_VecMedia.push_back(Media);
    return NoneError;
}

Uint32 CMkSdp::ToString(MkString& SdpContent)
{
    if (m_Version.empty()
        || m_Origin.Empty()
        || m_SessionName.empty()
        || m_Connection.Empty()) {
        return InvalidParams;
    }
    SdpContent.clear();
    MkString TmpStr;
    SdpContent += "v=" + m_Version + MkEndLine;
    Uint32 ErrorCode = m_Origin.ToString(TmpStr);
    MkCheckErrorLog(ErrorCode, "packet origin failed\n");
    SdpContent += "o=" + TmpStr + MkEndLine;
    SdpContent += "s=" + m_SessionName + MkEndLine;
    if (!m_SessionDesc.empty()) {
        SdpContent += "i=" + m_SessionDesc + MkEndLine;
    }
    if (!m_Uri.empty()) {
        SdpContent += "u=" + m_Uri + MkEndLine;
    }
    if (!m_Email.empty()) {
        SdpContent += "e=" + m_Email + MkEndLine;
    }
    if (!m_PhoneNumber.empty()) {
        SdpContent += "p=" + m_PhoneNumber + MkEndLine;
    }

    m_Connection.ToString(TmpStr);
    SdpContent += "c=" + TmpStr + MkEndLine;

    if (!m_BandWidth.Empty()) {
        m_BandWidth.ToString(TmpStr);
        SdpContent += "b=" + TmpStr + MkEndLine;
    }
    m_TimeDesc.ToString(TmpStr);
    SdpContent += "t=" + TmpStr + MkEndLine;
    if (NoneError == m_TimeDesc.RepeatTimesToString(TmpStr)) {
        SdpContent += "r=" + TmpStr + MkEndLine;
    }

    if (!m_MapTimeZones.empty()) {
        SdpContent += "z=";
        MkMapString::iterator itTime = m_MapTimeZones.begin();
        for (; itTime != m_MapTimeZones.end(); itTime++) {
            SdpContent += itTime->first + " " + itTime->second;
        }
        SdpContent += MkEndLine;
    }


    MkMapString::iterator itEnc = m_MapEncryptionKey.begin();
    for (; itEnc != m_MapEncryptionKey.end(); itEnc++) {
        SdpContent += "k=" + itEnc->first;
        if (!itEnc->second.empty()) {
            SdpContent += ":" + itEnc->second;
        }
        SdpContent += MkEndLine;
    }

    MkVector<CMkSdpAttribute>::iterator itAttr = m_VecAttribute.begin();
    for (; itAttr != m_VecAttribute.end(); itAttr++) {
        (itAttr)->ToString(TmpStr);
        SdpContent += "a=" + TmpStr + MkEndLine;
    }

    MkVector<CMkSdpMedia>::iterator itMedia = m_VecMedia.begin();
    for (; itMedia != m_VecMedia.end(); itMedia++) {
        (itMedia)->ToString(TmpStr);
        SdpContent += TmpStr;
    }
    return NoneError;
}

Uint32 CMkSdp::ParseContent(const MkString& SdpContent)
{
    MkString ReadLine;
    Uint32 LastPos = 0;
    Uint32 nPos = 0;
    Uint32 ErrorCode = NoneError;
    size_t LinePos = 0;
    MkString strKey, strValue;
    while (1) {
        LastPos = nPos;
        ErrorCode = CMkUtil::BufferReadLine(SdpContent, nPos, ReadLine);
        MkCheckErrorLog(ErrorCode, "read line:%s failed\n", SdpContent.substr(nPos).c_str());

        LinePos = ReadLine.find("=");
        if (MkString::npos == LinePos) {
            MkErrorLog("line:%s invalid\n", ReadLine.c_str());
            ErrorCode = InvalidParams;
            break;
        }

        strKey = ReadLine.substr(0, LinePos);
        strValue = ReadLine.substr(LinePos + 1);

        if ("m" == strKey) {
            break;
        } else if ("v" == strKey) {
            m_Version = strValue;
        } else if ("o" == strKey) {
            m_Origin.ParseContent(strValue);
        } else if ("s" == strKey) {
            m_SessionName = strValue;
        } else if ("i" == strKey) {
            m_SessionDesc = strValue;
        } else if ("u" == strKey) {
            m_Uri = strValue;
        } else if ("e" == strKey) {
            m_Email = strValue;
        } else if ("p" == strKey) {
            m_PhoneNumber = strValue;
        } else if ("c" == strKey) {
            m_Connection.ParseContent(strValue);
        } else if ("b" == strKey) {
            m_BandWidth.ParseContent(strValue);
        } else if ("t" == strKey) {
            m_TimeDesc.ParseContent(strValue);
        } else if ("r" == strKey) {
            m_TimeDesc.ParseRepeatTimes(strValue);
        } else if ("z" == strKey) {
            MkVectorString vecZone;
            ErrorCode = CMkUtil::StringSplit(strValue, " ", vecZone);
            for (size_t i = 0; i + 1 < vecZone.size(); i += 2) {
                m_MapTimeZones[vecZone[i]] = vecZone[i + 1];
            }
        } else if ("k" == strKey) {
            MkVectorString vecKey;
            ErrorCode = CMkUtil::StringSplit(strValue, ":", vecKey);
            MkCheckErrorLog(ErrorCode, "split key:%s failed\n", strValue.c_str());
            m_MapEncryptionKey[vecKey[0]] = vecKey.size() < 2 ? "" : vecKey[1];
        } else if ("a" == strKey) {
            CMkSdpAttribute Attr;
            if (NoneError == Attr.ParseContent(strValue)) {
                m_VecAttribute.push_back(Attr);
            }
        } else {
            MkWarningLog("recv unknow sdp msg, key is:%s value is:%s\n", strKey.c_str(), strValue.c_str());
        }
    }

    size_t FindPos = MkString::npos;
    while (1) {
        FindPos = SdpContent.find("m=", LastPos + 2); //offset m=
        if (MkString::npos != FindPos)  //find
        {
            CMkSdpMedia SdpMedia;
            if (NoneError == SdpMedia.ParseContent(SdpContent.substr(LastPos, FindPos - LastPos))) {
                m_VecMedia.push_back(SdpMedia);
            }
            LastPos = FindPos;
        } else {
            break;
        }
    }
    //the last media
    CMkSdpMedia SdpLastMedia;
    if (NoneError == SdpLastMedia.ParseContent(SdpContent.substr(LastPos))) {
        m_VecMedia.push_back(SdpLastMedia);
    }
    return NoneError;
}

CMkSdp::~CMkSdp()
{
    m_VecAttribute.clear();
    m_VecMedia.clear();
}